/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * Project Name: lmrp-android app
 * Create Time: 16-2-16 下午6:45
 */

package com.lenovo.mso2o.ui;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.text.method.HideReturnsTransformationMethod;
import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.lenovo.framework.base.InjectableActivity;
import com.lenovo.framework.biz.ContextManager;
import com.lenovo.framework.entity.AccessToken;
import com.lenovo.framework.entity.Res;
import com.lenovo.framework.rest.NetworkObserver;
import com.lenovo.framework.util.AppHelper;
import com.lenovo.framework.util.FPreferenceManager;
import com.lenovo.framework.util.TextHelper;
import com.lenovo.mso2o.R;
import com.lenovo.mso2o.biz.AccountManagerImpl;
import com.lenovo.mso2o.conf.BizErrorCode;
import com.lenovo.mso2o.conf.ErrorCode;
import com.lenovo.mso2o.conf.MSConstants;
import com.lenovo.mso2o.entity.TokenRequest;
import com.lenovo.mso2o.rest.AuthAPI;
import com.lenovo.mso2o.rest.ServiceGenerator;
import com.lenovo.mso2o.rest.UserAPI;
import com.lenovo.mso2o.util.Utils;

import java.util.concurrent.TimeUnit;

import butterknife.Bind;
import butterknife.OnClick;
import butterknife.OnEditorAction;
import butterknife.OnTextChanged;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.schedulers.Schedulers;

/**
 * A login screen that offers login via email/password.
 */
public class LoginActivity extends InjectableActivity {

    public static final String UPDATE_TOKEN_TIME_LONG_AGO = "long_ago";
    private static final long UPDATE_DELAY_MILLIS = 2*1000;

    private AuthAPI accountAPI;
    private String aesPass;
    private Animation an;

    private boolean isOpen = false;

    /**
     * Keep track of the login task to ensure we can cancel it if requested.
     */
    // UI references.
    @Bind(R.id.account)
    EditText mAccountView;
    @Bind(R.id.password)
    EditText mPasswordView;
    @Bind(R.id.email_login_form)
    LinearLayout mMainLayout;
    @Bind(R.id.login_logoimg)
    ImageView mLogo_img;
    @Bind(R.id.account_sign_in_button)
    Button mLogin_btn;
    @Bind(R.id.forget_password)
    TextView mForgetPass;
    String account, password;

    /*
     * network request subscription
     */
    private Subscription _subscription;

    public LoginActivity() {
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        accountAPI = ServiceGenerator.createService(AuthAPI.class);

        // Set up the login form.
        boolean expire = getIntent().getBooleanExtra(LoginActivity.UPDATE_TOKEN_TIME_LONG_AGO, false);
        if (expire) {
            Utils.debounceToast(getString(R.string.expire_longago));
        }
        mAccountView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
        mPasswordView.setImeOptions(EditorInfo.IME_ACTION_DONE);
        mAccountView.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                hideKeyboard(mMainLayout);
                return false;
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                hideKeyboard(mMainLayout);
                return false;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {

            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                hideKeyboard(mMainLayout);
                return false;
            }
        });
        mPasswordView.setCustomSelectionActionModeCallback(new ActionMode.Callback() {

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                hideKeyboard(mMainLayout);
                return false;
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                hideKeyboard(mMainLayout);
                return false;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {

            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                hideKeyboard(mMainLayout);
                return false;
            }
        });
        populateAutoComplete();
        controlKeyboardLayout(mMainLayout, mForgetPass);
    }

    @OnTextChanged(R.id.account)
    void onAccountChange(CharSequence text , int v1, int v2, int v3){
        if (!TextHelper.isEmptyOrSpaces(password) && !TextHelper.isEmptyOrSpaces(text.toString())) {
            mLogin_btn.setEnabled(true);
        }else {
            mLogin_btn.setEnabled(false);
        }
        account = text.toString();
    }

    @OnTextChanged(R.id.password)
    void onPasswordChange(CharSequence text , int v1, int v2, int v3){
        if (!TextHelper.isEmptyOrSpaces(account) && !TextHelper.isEmptyOrSpaces(text.toString())) {
            mLogin_btn.setEnabled(true);
        }else {
            mLogin_btn.setEnabled(false);
        }
        password = text.toString();
    }

    @OnEditorAction(R.id.password)
    public boolean onPasswordEditorAction(TextView arg0, int actionId, KeyEvent arg2) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            hideKeyboard(mMainLayout);
            mLogin_btn.performClick();
            return true;
        }
        return false;
    }

    @Override
    protected int provideContentViewId() {
        return R.layout.activity_login;
    }

    @OnClick(R.id.account_sign_in_button)
    public void onSignin(View view) {
        hideKeyboard(view);
        attemptLogin();
    }

    @OnEditorAction(R.id.account)
    public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
        if (id == R.id.login || id == EditorInfo.IME_NULL) {
            attemptLogin();
            return true;
        }
        return false;
    }

    @OnClick(R.id.forget_password)
    public void onForgetPassword(View view) {
        /*
        hideKeyboard(view);
        Bundle bundle = new Bundle();
        bundle.putString(ActionBarFragmentActivity.FRAGMENT_CLASS_NAME, ForgetpassFragment.class.getName());
        bundle.putInt(ActionBarFragmentActivity.FRAGMENT_TITLE, R.string.getpassword);
        openActivity(ActionBarFragmentActivity.class, bundle);
        */
    }

    private void populateAutoComplete() {
        String account = FPreferenceManager.getString(MSConstants.ACCOUNT_SIGNED, "");
        String password = FPreferenceManager.getString(MSConstants.ACCOUNT_PASSWORD, "");
        if (!TextHelper.isEmptyOrSpaces(password)) {
            mPasswordView.setText(password);
        }
        if (!TextHelper.isEmptyOrSpaces(account)){
            mAccountView.setText(account);
            if (!TextHelper.isEmptyOrSpaces(password))
                mLogin_btn.setEnabled(true);
        }else {
            mLogin_btn.setEnabled(false);
        }
    }

    /**
     * Attempts to sign in or register the account specified by the login form.
     * If there are form errors (invalid email, missing fields, etc.), the
     * errors are presented and no actual login attempt is made.
     */
    private void attemptLogin() {
        // Reset errors.
        mAccountView.setError(null);
        mPasswordView.setError(null);

        // Store values at the time of the login attempt.
        final String account = mAccountView.getText().toString();
        final String password = mPasswordView.getText().toString();
//        try {
//            aesPass = AppHelper.encrypt("`h:LKoj$#Hi&T@h$8i%n^k-c#l~o^u*n+d",password);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        boolean cancel = false;
        View focusView = null;

        // Check for a valid password, if the user entered one.

        // Check for a valid account.
        if (TextUtils.isEmpty(account)||TextUtils.isEmpty(password)) {
            Utils.debounceToast(getString(R.string.error_field_required));
            focusView = mAccountView;
            cancel = true;
        }else if (TextUtils.isEmpty(password)) {
            Utils.debounceToast(getString(R.string.error_invalid_password));
            focusView = mPasswordView;
            cancel = true;
        } else {
            if (!TextHelper.isEmail(account) && !TextHelper.isPhoneNum(account) && !TextHelper.isAccount(account)) {
                Utils.debounceToast(getString(R.string.error_invalid_account));
                focusView = mAccountView;
                cancel = true;
            }
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            final String[] uid = new String[1];

            requestPermission(Manifest.permission.READ_PHONE_STATE, new Runnable() {
                @Override
                public void run() {
                    if (ContextCompat.checkSelfPermission(ContextManager.context(), Manifest.permission.READ_PHONE_STATE)
                                != PackageManager.PERMISSION_GRANTED) {
                        showShortToast(R.string.allow_permission_request);
                    } else {
                        uid[0] = AppHelper.uid();
                        login(account, password, uid[0]);
                    }
                }
            });
        }
    }

    private void login(final String account, final String password, final String uid) {
        String pass = org.jivesoftware.smack.util.Base64.encodeBytes(password.getBytes());
        String cid = FPreferenceManager.getString(MSConstants.KEY_GETUI_CID, "");
        String appversion = AppHelper.versionName();
        String osversion = android.os.Build.VERSION.RELEASE;
        // Show a progress spinner, and kick off a background task to
        // perform the user login attempt.
        showProgress(true);
        final TokenRequest req = new TokenRequest();
        req.setLoginname(account);
        req.setPassword(org.jivesoftware.smack.util.Base64.encodeBytes(pass.getBytes()));
        req.setAppversion(AppHelper.packageName() + appversion);
        req.setDeviceid(uid);
        req.setOsversion(osversion);
        req.setCid(cid);
        FPreferenceManager.putString(MSConstants.ACCOUNT_SIGNED, account);
        if(_subscription == null || _subscription.isUnsubscribed())
            _subscription = accountAPI.getAccessToken(req)
                // Started in onStart(), running until in onStop()
                .compose(this.<Res<AccessToken>>bindToLifecycle())
                .subscribeOn(Schedulers.io())
                .doOnTerminate(new Action0() {
                    @Override
                    public void call() {
                        _subscription = null;
                    }
                })
                    //丢掉点击后2s内的请求
                .throttleFirst(1, TimeUnit.SECONDS)
                    //3s内只接受一次请求操作
                .debounce(UPDATE_DELAY_MILLIS, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .unsubscribeOn(Schedulers.io())
                .subscribe(new NetworkObserver<Res<AccessToken>>() {
                    @Override
                    public void onFailure(String tip) {
                        showProgress(false);
                        Utils.debounceToast(tip);
                        mPasswordView.requestFocus();
                    }

                    @Override
                    public void onSuccess(final Res<AccessToken> accessToken) {
                        if (accessToken.getEcode() == 0) {
                            //no slide back here
                            requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, new Runnable() {
                                @Override
                                public void run() {
                                    if (ContextCompat.checkSelfPermission(ContextManager.context(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
                                            != PackageManager.PERMISSION_GRANTED) {
                                        showShortToast(R.string.allow_permission_request);
                                    } else {
                                        AccountManagerImpl.instance.setToken(accessToken.getResult());
                                        FPreferenceManager.putString(MSConstants.ACCOUNT_PASSWORD, password);
                                        FPreferenceManager.putString(MSConstants.ACCOUNT_USERNAME, account);
                                        //如果app是第一次登录, 初始化appconfig
                                        if (!FPreferenceManager.getBoolean(MSConstants.LOGIN_NOT_FIRST_TIME, false)) {
                                            initConfig();
                                            FPreferenceManager.putBoolean(MSConstants.LOGIN_NOT_FIRST_TIME, true);
                                        }
                                        openActivity(MainActivity.class);
                                        finish();
                                    }
                                }
                            });
                        } else {
                            ErrorCode bizErrorCode = BizErrorCode.errorMap.get(accessToken.getEcode());
                            if(bizErrorCode != null) {
                                if (BizErrorCode.SECURITY_AUTH_FAILED.getCode() == bizErrorCode.getCode()
                                    || BizErrorCode.SECURITY_DENY.getCode() == bizErrorCode.getCode()
                                    || BizErrorCode.SECURITY_NO_ACCOUNT.getCode() == bizErrorCode.getCode()
                                    ||BizErrorCode.SECURITY_WRONG_PWD.getCode() == bizErrorCode.getCode()){
                                    onFailure(getString(R.string.name_or_password_error));
                                }else {
                                    onFailure(bizErrorCode.getReason());
                                }
                            }else{
                                if(accessToken.getReason() != null && !TextUtils.isEmpty(accessToken.getReason()))
                                    onFailure(accessToken.getReason());
                                else
                                    onFailure(getString(R.string.unknown_error));
                            }
                        }
                    }
                });
    }

    private void initConfig(){
        Observable.create(new Observable.OnSubscribe<Object>() {
            @Override
            public void call(Subscriber<? super Object> subscriber) {
                FPreferenceManager.putBoolean(AccountManagerImpl.KEY_FASTBILLING, true);
                FPreferenceManager.putBoolean(AccountManagerImpl.KEY_FASTBILLING, true);
                AccountManagerImpl.syncAppConfigJson(ServiceGenerator.createService(UserAPI.class), false);
                subscriber.onNext(true);
                subscriber.onCompleted();
            }
        })
        .subscribeOn(Schedulers.io())
        .toBlocking()
        .subscribe();
    }




    /**
     * Shows the progress UI and hides the login form.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
    private void showProgress(final boolean show) {
        if(show)
            processPreview(null, null, true);
        else
            processDismiss();
    }


    @Override
    public void finish() {
        super.finish();
        overridePendingTransition(0, 0);
    }
    /**
     * @param root 最外层布局，需要调整的布局
     * @param scrollToView 被键盘遮挡的scrollToView，滚动root,使scrollToView在root可视区域的底部
     */
    private void controlKeyboardLayout(final View root, final View scrollToView) {
        root.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                            Rect rect = new Rect();
                            // 获取root在窗体的可视区域
                            root.getWindowVisibleDisplayFrame(rect);
                            // 获取root在窗体的不可视区域高度(被其他View遮挡的区域高度)
                            int rootInvisibleHeight = root.getRootView()
                                    .getHeight() - rect.bottom;
                            // 若不可视区域高度大于150，则键盘显示
                            if (rootInvisibleHeight > 150) {
                                    int[] location = new int[2];
                                    // 获取scrollToView在窗体的坐标
                                    scrollToView.getLocationInWindow(location);

                                    // 计算root滚动高度，使scrollToView在可见区域的底部
                                    int srollHeight = (location[1] + scrollToView
                                            .getHeight()) - rect.bottom;
                                    root.scrollTo(0, srollHeight);

                                    if(mLogo_img.getVisibility() == View.VISIBLE){
                                        an = new AlphaAnimation(1,0);
                                        an.setAnimationListener(new Animation.AnimationListener() {

                                            public void onAnimationStart(Animation animation) {
                                                // TODO Auto-generated method stub

                                            }

                                            public void onAnimationEnd(Animation animation) {
                                                // TODO Auto-generated method stub
                                                mLogo_img.setVisibility(View.INVISIBLE);
                                            }

                                            public void onAnimationRepeat(Animation animation) {
                                                // TODO Auto-generated method stub

                                            }

                                        });
                                        an.setDuration(200);
                                        mLogo_img.setAnimation(an);
                                        mLogo_img.startAnimation(an);
                                    }
                        } else {
                            // 键盘隐藏
                                root.scrollTo(0, 0);
                                if(mLogo_img.getVisibility() == View.INVISIBLE){
                                    an = new AlphaAnimation(0,1);
                                    an.setAnimationListener(new Animation.AnimationListener() {

                                        public void onAnimationStart(Animation animation) {
                                            // TODO Auto-generated method stub

                                        }

                                        public void onAnimationEnd(Animation animation) {
                                            // TODO Auto-generated method stub
                                            mLogo_img.setVisibility(View.VISIBLE);
                                        }

                                        public void onAnimationRepeat(Animation animation) {
                                            // TODO Auto-generated method stub

                                        }

                                    });
                                    an.setDuration(200);
                                    mLogo_img.setAnimation(an);
                                    mLogo_img.startAnimation(an);
                                }
                        }
                    }
                });
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if( keyCode == KeyEvent.KEYCODE_BACK){
            if(an !=null){
                an.cancel();
            }
            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
            isOpen = imm.isActive();//isOpen若返回true，则表示输入法打开
            if(isOpen){
                hideKeyboard(findViewById(android.R.id.content));
            }else{
                System.exit(0);
            }
        }
        return super.onKeyDown(keyCode, event);
    }
}

